iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0
Software Development

一起看無間道學EdgeDB系列 第 24

[Day24] - EdgeDBSet概念加強

  • 分享至 

  • xImage
  •  

EdgeDBSet是整個EdgeDB的核心,今天我們特別做個整理,加強一下大家對它的認識。

Union

union幫助大家找出兩個EdgeDBSet的所有元素。例如:

select {1, 2, 3, 3} union {3, 3, 4, 5};
{1, 2, 3, 3, 3, 3, 4, 5}

Except

except幫助大家找出在第一個EdgeDBSet卻不在第二個EdgeDBSet的元素。例如:

select {1, 2, 3, 3} except {3, 3, 4, 5};
{1, 2}

Intersect

intersect幫助大家找出在第一個EdgeDBSet也在第二個EdgeDBSet的元素。例如:

select {1, 2, 3, 3} intersect {3, 3, 4, 5};
{3, 3}

Distinct

distinct幫大家找出EdgeDBSet中所有獨特的元素,也就是說該EdgeDBSet中不會有相同的元素,就像是Python中的set一樣。

 select distinct {1, 2, 3, 3};
{1, 2, 3}

?? operator

??可以幫助我們選擇第一個出現的非空EdgeDBSet。例如:

select <int64>{} ?? {1};
{1}

由於空EdgeDBSet也是需要型別的,所以上面的空EdgeDBSet需要加上<int64>。由於??左邊是一個空EdgeDBSet,所以??會返回{1}

假設??兩個都為空EdgeDBSet,則會返回後面那個。例如:

with a:= (select <int64>{} ?? <float64>{})
select a is float64;
{true}

或許您會覺得int64float64不是同一型別,為什麼可以比較呢?這是因為EdgeDB為了方便使用者,會對整數及浮點數做自動的型別轉換(預設的整數型態為int64,而預設的浮點數型態為float64)。例如:

select {1} + {2.3};
{3.3}

這樣的轉換不只出現在整數與浮點數間,整數與整數間或是浮點數與浮點數間也會進行。例如:

with a:= (select <int16>{1} + <int32>{2})
select a is int32;
{true}

或是:

with a:= (select <float32>{1.1} + {1.1})
select a is float64;
{true}

Exists

exists可以幫助我們判斷所傳入的是否為空EdgeDBSet。例如:

select exists({1});
{true}

當想在兩個EdgeDBSet中進行選擇時,exists??的功能類似。例如:

with a:= <int64>{},
     b:= {1}
select a if exists(a) else b;

也可以寫為:

with a:= <int64>{},
     b:= {1}
select a ?? b;

兩者的結果都是b

{1}

運算

EdgeDBSet可以進行多種運算。例如:

+ operator

select {5} + {2};
{7}

- operator

select {5} - {2};
{3}

* operator

select {5} * {2};
{10}

/ operator

select {5} / {2};
{2.5}

// operator

select {5} // {2};
{2}

% operator

select {5} % {2};
{1}

Element-wise

EdgeDBSet的各種運算看起來相當直觀,有時候會讓人忘了它的運算其實是element-wise。例如:

select {1, 2} + {3, 4};
{4, 5, 5, 6}

element-wise的意思是EdgeDBSet內的每個元素都會各別參與一次計算。所以上面的{4, 5, 5, 6}分別是1+31+42+32+4的結果。

++ operator

EdgeDBSet內元素為str,而需要與其它內部元素也是strEdgeDBSet連接時,需要使用++。例如:

select {"a", "b"} ++ {"c", "d"};
{'ac', 'ad', 'bc', 'bd'}

如果寫成:

select {"a", "b"} + {"c", "d"};

會報錯:

error: InvalidTypeError: operator '+' cannot be applied to operands of type 'std::str' and 'std::str'

EdgeDBSet

EdgeDBSet的計算中遇到空EdgeDBSet時,會立刻返回該種型別的空EdgeDBSet。例如:

select <int64>{} + {1, 2};
{}

或是:

select <str>{} ++ {"a", "b"};
{}

我們可以透過introspecttypeof來觀察返回的空EdgeDBSet

with a:=(select <int64>{} + {1, 2})
select (introspect typeof a) {*};
{
  schema::ScalarType {
    final: false,
    is_final: false,
    abstract: false,
    is_abstract: false,
    id: 00000000-0000-0000-0000-000000000105,
    name: 'std::int64',
    internal: false,
    builtin: true,
    computed_fields: [],
    expr: {},
    from_alias: false,
    is_from_alias: false,
    inherited_fields: [],
    default: {},
    enum_values: {},
    arg_values: {},
  },
}

可以看出其name property顯示其為std::int64

Shape

考慮schema如下:

abstract type Portfolio {
  multi stocks: Stock
}

type ValueInvesting extending Portfolio;
type TechnicalAnalysis extending Portfolio;

type Stock {
    required name: str {
        constraint min_len_value(4);
        constraint max_len_value(5);      
    }

    required eps: float64
}

我們這裡模擬一個股市的投資情境:

  • Portfolio abstract type為一投資組合,內部含有多個Stock object,供ValueInvesting objectTechnicalAnalysis objectextending
  • ValueInvesting object代表價值投資學派選股法。
  • TechnicalAnalysis object代表技術分析學派選股法
  • Stock object含有一個name property及一個eps property,用以記錄股票名字及比益比。

接著執行下列query,insert五個Stock object、一個ValueInvesting object及一個TechnicalAnalysis object

with stocks:= {
    (name:="好棒棒實業", eps:= 5),
    (name:="井噴金控", eps:= 12),
    (name:="歐印集團", eps:= 15),
    (name:="雜空企業", eps:= 18),
    (name:="多娃廚房", eps:= 40),
}
for stock in stocks
union (
    insert Stock {
        name:= stock.name, 
        eps:= stock.eps
    }
);


insert ValueInvesting {
    stocks:= (
        select Stock 
        filter .name in {"好棒棒實業", "井噴金控", "歐印集團", "雜空企業"}
    )
};


insert TechnicalAnalysis {
    stocks:= (
        select Stock 
        filter .name in {"井噴金控", "歐印集團", "雜空企業", "多娃廚房"}
    )
};

我們可以透過下面query,列出兩個學派共同選中的股票:

select ValueInvesting.stocks intersect TechnicalAnalysis.stocks {**};
{
  default::Stock {id: d5718b48-549a-11ef-82dd-dbb5b0359637},
  default::Stock {id: d5718b98-549a-11ef-82dd-13f3b149f61d},
  default::Stock {id: d5718bca-549a-11ef-82dd-a39cbfb647d8},
}

雖然我們加上了{**},但卻沒有顯示出Stockshape,不方便觀察。這是因為set operation在做運算之後(例如這邊的intersect),shape不會保存。

我們需要使用with來幫忙改寫query如下:

with common_stocks:= (ValueInvesting.stocks intersect TechnicalAnalysis.stocks)
select common_stocks {name, eps};
{
  default::Stock {name: '雜空企業', eps: 18},
  default::Stock {name: '歐印集團', eps: 15},
  default::Stock {name: '井噴金控', eps: 12},
}

這麼一來,我們就可以觀察出有三檔股票,是兩個學派都擁有的標的。


上一篇
[Day23] - 十幕:我想做個好人
下一篇
[Day25] - 進階Schema介紹
系列文
一起看無間道學EdgeDB30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言